<template>
  <el-tabs type="border-card">
    <el-tab-pane label="初始化字典">

      <kv class="flow" style="position: absolute;right:10px;top:10px;z-index:99;background-color: #cbf4e4">
        <template #k>
          <div class="k" style="">
            <div>上传文件</div>
          </div>
        </template>
        <el-upload
            ref="upload"
            drag
            v-model:file-list="$data.files"
            :limit="1"
            :auto-upload="false"
            :on-change="fileChange"
            :key="$data.version"
            accept=".dict"
        >
          <el-icon class="el-icon--upload">
            <upload-filled/>
          </el-icon>
          <div class="el-upload__text">
            拖动上传 或 点击上传
          </div>
          <template #tip>
            <div class="el-upload__tip">
              集合名.dat
            </div>
          </template>
        </el-upload>

      </kv>

      <el-input type="textarea" v-model="$data.initDictMapString"
                :autosize="{ minRows: 12, maxRows: 18 }"></el-input>
    </el-tab-pane>

    <el-tab-pane label="dict-mapping.dict">
      <div
          style="position: absolute;right:25px;top:25px; z-index: 999;display: flex;flex-direction: column;align-items: flex-end;gap:10px;">

        <el-button v-if="$data.dictMap" type="danger"
                   @click="regen_click">
          重新生成 dict-mapping.dict
        </el-button>
        <el-button v-if="$data.dictMap" type="primary"
                   @click="jv.saveFileWithPicker(showJson($data.dictMap), 'dict-mapping.dict')">
          保存 dict-mapping.dict
        </el-button>
      </div>
      <el-input type="textarea" :value="showJson($data.dictMap)" readonly
                :autosize="{ minRows: 12, maxRows: 18 }"></el-input>
    </el-tab-pane>

    <el-tab-pane label="api-def.json">
      <el-button v-if="$data.apiDef" type="primary" style="position: absolute;right:25px;top:25px; z-index: 999"
                 @click="jv.saveFileWithPicker(showJson({defaultGroup: $data.apiDef }), 'api-def.json')">
        保存 api-def.json
      </el-button>
      <el-input type="textarea" readonly :value="showJson({defaultGroup: $data.apiDef })"
                :autosize="{ minRows: 12, maxRows: 18 }"></el-input>
    </el-tab-pane>
    <el-tab-pane label="api-def-mapping.json">
      <el-button v-if="$data.param" type="primary" style="position: absolute;right:25px;top:25px; z-index: 999"
                 @click="jv.saveFileWithPicker(showJson($data.param), 'api-def-mapping.json')">
        保存 api-def-mapping.json
      </el-button>
      <el-input type="textarea" readonly :value="showJson($data.param)"
                :autosize="{ minRows: 12, maxRows: 18 }"></el-input>
    </el-tab-pane>
    <el-tab-pane label="markdown">
      <el-button v-if="$data.doc" type="primary" style="position: absolute;right:25px;top:25px; z-index: 999"
                 @click="jv.saveFileWithPicker($data.doc, '接口文档.txt')">
        保存接口文档
      </el-button>
      <el-input type="textarea" readonly v-model="$data.doc" :autosize="{ minRows: 12, maxRows: 18 }"></el-input>
    </el-tab-pane>
  </el-tabs>
</template>
<script setup>

const showJson = obj => {
  return JSON.stringify(obj.toKeySortedJson(), null, '  ')
}

// 定义选项
defineOptions({
  name: "apiDefCom",
  inheritAttrs: false,
});


const $props = defineProps({
  apis: {type: Array, default: () => []},
  level: {type: Number, default: 1}
});


//定义data
const $data = reactive({
  initDictMapString: "",
  dictMap: {},
  apiDef: {},
  param: {},
  doc: "",
  files: [],
  version: 1,

  dict: []
})


const fileChange = (uploadFile, uploadFiles) => {
  $data.version++;
  // uploadFile 是当前操作的文件对象，包含原生的 File 对象
  const file = uploadFile.raw // .raw 属性是原生的 File 对象

  if (!file) {
    return;
  }
  const reader = new FileReader()

  reader.onload = (e) => {
    // e.target.result 就是文件的内容
    $data.initDictMapString = e.target.result
  }

  reader.onerror = () => {
    $data.initDictMapString = '读取文件失败'
  }

  // 开始读取文件为文本 (UTF-8)
  reader.readAsText(file)

}

const regen_click = (pan, ev) => {

  jv.$http.get("/open/dict").then(res => {
    $data.dict = res.data.data;

    $data.dictMap = JSON.parse($data.initDictMapString || "{}");

    //会重新生成 $data.dictMap
    load($props.apis);
  });

}


const getWord = word => {
  var lower = word.toLowerCase();
  var encoded = $data.dictMap[lower];
  if (!encoded) {
    var len = word.length;
    if (len == 1) {
      len = 2;
    }
    if (len > 12) {
      len = 12;
    }

    //先找在该单词长度是长度-1,长度+1
    var subDict = $data.dict.filter(it => it.length.Between(len - 1, len + 1) && it != word);

    //如果结果小于3个，则再扩大范围
    if (subDict.length < 3) {
      subDict.addAll($data.dict.filter(it => it.length.Between(word.length / 2, word.length * 2) && it != word))
    }

    //最后由于字典数量太少， 则使用全部
    if (subDict.length < 3) {
      subDict = $data.dict;
    }

    var index = parseInt(Math.random() * 5000) % subDict.length;
    encoded = subDict[index];

    //把已使用的移除
    $data.dict.removeItem(encoded);
    $data.dictMap[word] = encoded;
  }

  //判断首字母是否是大写。
  var isUpper = word[0].getUpperLetterCount() == 1;
  if (isUpper) {
    return encoded[0].toUpperCase() + encoded.slice(1);
  }

  return encoded || "";
}


/**
 * 翻译, 风格统一，大驼峰，小驼峰，中划线，下划线，斜线，点 , {}.
 * 并把后端路由 {}转为前端路由， 如 /user/detail/{id} --> /user/detail/:id
 * @param word
 */
const translateString = word => {
  if (!word) {
    return "";
  }
  if (word.getDigitCount() == word.length) {
    return word;
  }
  //按大小写拆
  var isAllUpper = word.getUpperLetterCount() == word.length;
  var isAllLower = word.getLowerLetterCount() == word.length;

  if (isAllUpper || isAllLower) {
    return getWord(word);
  }

  //先按 / 拆分。
  if (word.includes("/")) {
    return word.replace(/([^/])+/g, it => translateString(it))
  }

  if (word.includes(".")) {
    return word.replace(/([^.])+/g, it => translateString(it))
  }

  if (word.includes("{")) {
    return word.replace(/\{([^}])+\}/g, it => ":" + translateString(it.slice(1, -1)))
  }


  if (word.includes("_")) {
    return word.replace(/([^_])+/g, it => translateString(it))
  }

  //按连字符以及下划线拆。
  if (word.includes("-")) {
    return word.replace(/([^-])+/g, it => translateString(it))
  }

  //保留数字，数字不混淆
  if (word.getDigitCount() > 0) {
    return word.split(/(\d+)/g).map(it => translateString(it)).join("");
  }


  if (word.getLetterCount() != word.length) {
    console.error(`混淆的 ${word} 还能继续拆!`)
    return word;
  }


  const w1Lower = word[0].getLowerLetterCount() == 1;

  const wordKStyle = word.getKebabCase()
  const ret = wordKStyle.split("-")
      .map(it => {
        const w = getWord(it);
        if (!w) {
          return "";
        }


        return w[0].toUpperCase() + w.slice(1);
      }).join("");

  if (!ret) {
    return ""
  }

  if (w1Lower) {
    return ret[0].toLowerCase() + ret.slice(1);
  }

  return ret;
}


const genApiDef = apis => {
  var map = new Map();
  apis.forEach(api => {
    map[api] = translateString(api);
  });

  return map;
}

const genParam = ps => {
  var ret = {};
  ps.forEach(it => ret[it] = translateString(it));
  return ret;
}

const genDoc = apis => {
  return jv.dev.api_encode_markdown($props.apis, $props.level, $data.apiDef, $data.param);
}

const getPs = (requestHeaderParameters, responseHeaderParameters, requestUrlQueryParameters) => {
  var list = new Set();
  requestHeaderParameters.forEach(headerParameter => {
    list.add(headerParameter.key.toLowerCase());
  })

  responseHeaderParameters.forEach(headerParameter => {
    list.add(headerParameter.key.toLowerCase());
  })

  requestUrlQueryParameters.forEach(parameter => {
    list.add(parameter.key);
  })


  return list;
}

const getPsItems = (requestBodyParameters, responseBodyParameters) => {
  var list = new Set();
  jv.recursionJson(requestBodyParameters, it => {
    if (it.items) {
      list.addAll(it.items.map(it2 => it2.key));
    }

  });

  jv.recursionJson(responseBodyParameters, it => {
    if (it.items) {
      list.addAll(it.items.map(it2 => it2.key));
    }
  });

  return list;
}

const load = (apis) => {
  $data.apiDef = genApiDef(apis.map(it => it.url));

  var ps = new Set();
  ps.addAll(jv.dev.th_common_headers)

  apis.forEach(it => {
    var ps2 = getPs(it.requestHeaderParameters, it.responseHeaderParameters, it.requestUrlQueryParameters);
    ps.addAll(ps2)

    var ps3 = getPsItems(it.requestBodyParameters, it.responseBodyParameters);
    ps.addAll(ps3)
  });
  $data.param = genParam(Array.from(ps));

  $data.doc = genDoc(apis);
}

watch($props.apis, function (v) {
  load(v);
}, {immediate: false});

</script>